///////////////////////////////////////////////////////////////////////////
//
//  @ File      :   res_manager.cpp
//  @ Author    :   zhoukaifeng<zhoukaifeng@kingsoft.com>
//  @ DateTime  :   2014-10-24 15:44:18 
//  @ Brief     :
//
///////////////////////////////////////////////////////////////////////////

#include "res_manager.h"

static GdiPlusInit init;

void ResManager::SetResourcePath(LPCTSTR lpszResPath)
{
    m_strResourcePath = lpszResPath;
    if (m_strResourcePath[m_strResourcePath.GetLength() - 1] == L'\\'
        || m_strResourcePath[m_strResourcePath.GetLength() - 1] == L'/')
    {
        m_strResourcePath = m_strResourcePath.Left(m_strResourcePath.GetLength() - 1);
    }
}

void ResManager::SetResourceModule(HINSTANCE hResMoudle)
{
    m_hResourceModule = hResMoudle;
}

BOOL ResManager::LoadBmpFromResourceID(const CString& strResID, HBITMAP &hBitmap)
{
    if (!m_strResourcePath.IsEmpty())
    {
        CString strFileName;

        strFileName.Format(L"%s\\%s.bmp", m_strResourcePath, strResID);

        hBitmap = (HBITMAP)::LoadImage(NULL, strFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

        if (hBitmap != NULL)
        {
            return TRUE;
        }
    }

    UINT uResID = 0;
    if (!GetResourceIntID(strResID, uResID))
    {
        return FALSE;
    }

    if (m_hResourceModule)
    {
        hBitmap = ::LoadBitmap(m_hResourceModule, MAKEINTRESOURCE(uResID));
        if (hBitmap != NULL)
        {
            return TRUE;
        }
    }

    hBitmap = ::LoadBitmap((HINSTANCE)&__ImageBase, MAKEINTRESOURCE(uResID));
    if (hBitmap)
    {
        return TRUE;
    }

    return hBitmap != NULL;
}


BOOL ResManager::LoadImgFromResourceID(const CString& strResID, LPCTSTR lpszResType, Gdiplus::Image* &pImg)
{
    CStringA strResource;

    BOOL bRet = LoadResource(strResID, strResource, lpszResType);
    if (!bRet)
    {
        return FALSE;
    }

    int len = strResource.GetLength();

    HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, len);
    BYTE* pMem = (BYTE*)::GlobalLock(hMem);

    memcpy(pMem, (LPCSTR)strResource, len);

    IStream* pStm = NULL;
    ::CreateStreamOnHGlobal(hMem, FALSE, &pStm);

    pImg = Gdiplus::Image::FromStream(pStm);

     pStm->Release();
    ::GlobalUnlock(hMem);
    ::GlobalFree(hMem);

    return TRUE;
}

BOOL ResManager::LoadResource(const CString& strResID, CStringA &strBuffRet, LPCTSTR lpszResType)
{
    BOOL bRet = _LoadResourceFromResourcePath(strResID, strBuffRet, lpszResType);
    if (bRet)
    {
        return TRUE;
    }

    UINT uResID = 0;
    if (!GetResourceIntID(strResID, uResID))
    {
        return bRet;
    }

    if (m_hResourceModule)
    {
        bRet = _LoadResourceFromModule(m_hResourceModule, uResID, strBuffRet, lpszResType);
        if (bRet)
        {
            return TRUE;
        }
    }

    bRet = _LoadResourceFromModule((HINSTANCE)&__ImageBase, uResID, strBuffRet, lpszResType);
    if (bRet)
    {
        return TRUE;
    }

    return bRet;
}

BOOL ResManager::_LoadResourceFromModule(HINSTANCE hModule, UINT uResID, CStringA &strRet, LPCTSTR lpszResType)
{
    HRSRC hRsrc = ::FindResource(hModule, MAKEINTRESOURCE(uResID), lpszResType);

    if (hRsrc == NULL)
        return FALSE;

    DWORD dwSize = ::SizeofResource(hModule, hRsrc); 
    if (dwSize == 0)
        return FALSE;

    HGLOBAL hGlobal = ::LoadResource(hModule, hRsrc); 
    if (hGlobal == NULL)
        return FALSE;

    LPVOID pBuffer = ::LockResource(hGlobal); 
    if (pBuffer == NULL)
        return FALSE;

    LPSTR lpStrRet = strRet.GetBuffer(dwSize + 1);
    if (lpStrRet != NULL)
    {
        memcpy(lpStrRet, pBuffer, dwSize);
    }
    strRet.ReleaseBuffer(dwSize + 1);

    ::FreeResource(hGlobal);

    return TRUE;
}

BOOL ResManager::_LoadResourceFromResourcePath(const CString& strResID, CStringA &strBuffRet, LPCTSTR lpszResType)
{
    BOOL bRet = FALSE;

    if (!m_strResourcePath.IsEmpty())
    {
        CString strFileName;
        CString strResIDTmp = strResID;

        if (strResIDTmp.GetLength() > 0
            && (strResIDTmp[0] == L'\\'
            || strResIDTmp[0] == L'/'))
        {
            strResIDTmp = strResIDTmp.Right(strResIDTmp.GetLength() - 1);
        }

        strFileName.Format(L"%s\\%s.%s", m_strResourcePath, strResIDTmp, lpszResType);

        HANDLE hFile = ::CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, 
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        if (hFile != INVALID_HANDLE_VALUE)
        {
            DWORD dwSize = ::GetFileSize(hFile, NULL);
            if (dwSize != 0)
            {
                DWORD dwRead = 0;
                bRet = ::ReadFile(hFile, strBuffRet.GetBuffer(dwSize + 10), dwSize, &dwRead, NULL);
                if (bRet && dwRead == dwSize)
                {
                    strBuffRet.ReleaseBuffer(dwSize);
                    ::CloseHandle(hFile);
                    return TRUE;
                }
                strBuffRet.ReleaseBuffer(0);
            }
            ::CloseHandle(hFile);
        }
    }

    return bRet;
}

BOOL ResManager::GetResourceIntID(const CString& strResID, UINT& uResID)
{
    uResID = 0;
    for (int i = 0; i < strResID.GetLength(); ++i)
    {
        if (strResID[i] < L'0' || strResID[i] > L'9')
        {
            return FALSE;
        }
        else 
        {
            uResID *= 10;
            uResID += (strResID[i] - L'0');
        }
    }

    return TRUE;
}